/*
 * cudanCudaArrayMemory.cpp
 *
 *  Created on: Dec 11, 2009
 *      Author: daniel
 */

namespace CUDAN
{
	// Default Contructor.
	template<typename T, int D>
	CudaArrayMemory<T,D>::CudaArrayMemory() : array(NULL), DeviceMemory<T,D>()
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>::CudaArrayMemory()" << std::endl;
#endif
	}

	// Construct a CudaArrayMemory by copying data from the host to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>::CudaArrayMemory(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>::CudaArrayMemory(HostMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a CudaArrayMemory by copying data from the device to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>::CudaArrayMemory(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>::CudaArrayMemory(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a CudaArrayMemory by copying data from global to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>::CudaArrayMemory(GlobalMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>::CudaArrayMemory(GlobalMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a CudaArrayMemory by copying data from a cudaArray to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>::CudaArrayMemory(CudaArrayMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>::CudaArrayMemory(CudaArrayMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a CudaArrayMemory by copying data from a texture to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>::CudaArrayMemory(TextureMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>::CudaArrayMemory(TextureMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a CudaArrayMemory by copying data from the host to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(HostMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Construct a CudaArrayMemory by copying data from a device to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Construct a CudaArrayMemory by copying data from a global to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(GlobalMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(GlobalMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Construct a CudaArrayMemory by copying data from a cudaArray to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(CudaArrayMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(CudaArrayMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Construct a CudaArrayMemory by copying data from a texture to the array.
	template<typename T, int D>
	CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(TextureMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>* CudaArrayMemory<T,D>::operator=(TextureMemory<T,D>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Destructor.
	template<typename T, int D>
	CudaArrayMemory<T,D>::~CudaArrayMemory()
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,D>::~CudaArrayMemory()" << std::endl;
#endif
	}

	// Free memory in the CudaArray.
	template<typename T, int D>
	void CudaArrayMemory<T,D>::freeMemory()
	{
#ifdef _DEBUG
		std::cout << "void CudaArrayMemory<T,D>::freeMemory()" << std::endl;
#endif
		// Free the cudaArray.
		cudaFreeArray(this->array);

		// Free the dimension size on the device.
		cudaFree(this->sizeDimGPU);

		// Reset member values.
		this->array = NULL;
		this->size = 0;
		this->sizeDim = DimensionSizeVector(D);
	}

	// Print data in cudaArray to stdout.
	template<typename T, int D>
	void CudaArrayMemory<T,D>::print()
	{
#ifdef _DEBUG
		std::cout << "void CudaArrayMemory<T,D>::print()" << std::endl;
#endif
		// Copy cudaArray to the host.
		HostMemory<T,D> h(this);

		// Print out host data.
		h.print();

		// Free the temporary host data.
		h.freeMemory();
	}

	// Print data at specified index in cudaArray to stdout.
	template<typename T, int D>
	void CudaArrayMemory<T,D>::print(DimensionSizeVector& index)
	{
#ifdef _DEBUG
		std::cout << "void CudaArrayMemory<T,D>::print(DimensionSizeVector& index)" << std::endl;
#endif
		// Copy cudaArray to the host.
		HostMemory<T,D> h(this);

		// Print out host data at index.
		h.print(index);

		// Free the temporary host data.
		h.freeMemory();
	}

	// Allocate memory on the device for the cudaArray.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::allocateMemory(DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::allocateMemory(DimensionSizeVector& dim)" << std::endl;
#endif
		// Boundary check dimensions.
		for(int i=0; i<D; i++) if(dim[i] < 0) return false;

		int width, height, depth;

		// Set the width, height, depth.
		switch(D) {
		case 1:
			width = dim[0];
			height = 1;
			depth = 0;
			break;
		case 2:
			width = dim[0];
			height = dim[1];
			depth = 0;
			break;
		}

		// Create a channel description of type T.
		this->channelDesc = cudaCreateChannelDesc<T>();

		// Specify the size of the array with cudaExtent.
		this->extent = make_cudaExtent(width, height, depth);

		// Mallloc the 3D array on the device.
		if(cudaMalloc3DArray(&this->array, &this->channelDesc, this->extent) == cudaSuccess) {
			// Set the size of the array.
			this->setSize(dim);
			return true;
		}

		return false;
	}

	// Copy data from the host to the cudaArray.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyFrom(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyFrom(HostMemory<T,D>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for the cudaArray.
		if(this->size != copy->size) {
			if(this->array != NULL) this->freeMemory();
			this->allocateMemory(copy->sizeDim);
		}

		// Copy data.
		if(cudaMemcpyToArray(this->array, 0, 0, copy->memory, sizeof(T) * this->size, cudaMemcpyHostToDevice) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from the device to the cudaArray.
	// Method for copying data specified in copy's method.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyFrom(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyFrom(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		return copy->copyTo(this);
	}

	// Copy data from a global to the cudaArray.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyFrom(GlobalMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyFrom(GlobalMemory<T,D>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for the cudaArray.
		if(this->size != copy->size) {
			if(this->array != NULL) this->freeMemory();
			this->allocateMemory(copy->sizeDim);
		}

		// Copy data.
		if(cudaMemcpyToArray(this->array, 0, 0, copy->memory, sizeof(T) * this->size, cudaMemcpyDeviceToDevice) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from a cudaArray to the cudaArray.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyFrom(CudaArrayMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyFrom(CudaArrayMemory<T,D>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for the cudaArray.
		if(this->size != copy->size) {
			if(this->array != NULL) this->freeMemory();
			this->allocateMemory(copy->sizeDim);
		}

		// Copy data.
		if(cudaMemcpyArrayToArray(this->array, 0, 0, copy->array, 0, 0, sizeof(T) * this->size, cudaMemcpyDeviceToDevice) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from a texture to the cudaArray.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyFrom(TextureMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyFrom(TextureMemory<T,D>* copy)" << std::endl;
#endif
		// Copy cudaArray in texture to the cudaArray.
		return this->copyFrom(&copy->cudaArray);
	}

	// Copy data from the cudaArray to the host.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyTo(HostMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyTo(HostMemory<T,D>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for the host.
		if(this->size != copy->size) {
			if(copy->memory != NULL) copy->freeMemory();
			copy->allocateMemory(this->sizeDim);
		}

		// Copy data.
		if(cudaMemcpyFromArray(copy->memory, this->array, 0, 0, sizeof(T) * this->size, cudaMemcpyDeviceToHost) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from the cudaArray to the device.
	// Method for copying data specified in copy's method.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyTo(DeviceMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyTo(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		return copy->copyFrom(this);
	}

	// Copy data from the cudaArray to a global.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyTo(GlobalMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyTo(DeviceMemory<T,D>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for a global.
		if(this->size != copy->size) {
			if(copy->memory != NULL) copy->freeMemory();
			copy->allocateMemory(this->sizeDim);
		}

		// Copy data.
		if(cudaMemcpyFromArray(copy->memory, this->array, 0, 0, sizeof(T) * this->size, cudaMemcpyDeviceToDevice) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from the cudaArray to a cudaArray.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyTo(CudaArrayMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyTo(CudaArrayMemory<T,D>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for a cudaArray.
		if(this->size != copy->size) {
			if(copy->memory != NULL) copy->freeMemory();
			copy->allocateMemory(this->sizeDim);
		}

		// Copy data.
		if(cudaMemcpyArrayToArray(copy->array, 0, 0, this->array, 0, 0, sizeof(T) * this->size, cudaMemcpyDeviceToDevice) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from the cudaArray to a texture.
	template<typename T, int D>
	bool CudaArrayMemory<T,D>::copyTo(TextureMemory<T,D>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,D>::copyTo(TextureMemory<T,D>* copy)" << std::endl;
#endif
		return copy->copyFrom(this);
	}

	/////////3D///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	// Default Constructor.
	template<typename T>
	CudaArrayMemory<T,3>::CudaArrayMemory()
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>::CudaArrayMemory()" << std::endl;
#endif
	}

	// Construct a 3D CudaArrayMemory by copying data from the host to the array.
	template<typename T>
	CudaArrayMemory<T,3>::CudaArrayMemory(HostMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>::CudaArrayMemory(HostMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a 3D CudaArrayMemory by copying data from a device to the array.
	template<typename T>
	CudaArrayMemory<T,3>::CudaArrayMemory(DeviceMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>::CudaArrayMemory(DeviceMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a 3D CudaArrayMemory by copying data from a global to the array.
	template<typename T>
	CudaArrayMemory<T,3>::CudaArrayMemory(GlobalMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>::CudaArrayMemory(GlobalMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a 3D CudaArrayMemory by copying data from a cudaArray to the array.
	template<typename T>
	CudaArrayMemory<T,3>::CudaArrayMemory(CudaArrayMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>::CudaArrayMemory(CudaArrayMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a 3D CudaArrayMemory by copying data from a texture to the array.
	template<typename T>
	CudaArrayMemory<T,3>::CudaArrayMemory(TextureMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>::CudaArrayMemory(TextureMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);
	}

	// Construct a 3D CudaArrayMemory by copying data from the host to the array.
	template<typename T>
	CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(HostMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(HostMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Construct a 3D CudaArrayMemory by copying data from a device to the array.
	template<typename T>
	CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(DeviceMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(DeviceMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Construct a 3D CudaArrayMemory by copying data from a global to the array.
	template<typename T>
	CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(GlobalMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(GlobalMemory<T,3>* copy))" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Construct a 3D CudaArrayMemory by copying data from a cudaArray to the array.
	template<typename T>
	CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(CudaArrayMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(CudaArrayMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Construct a 3D CudaArrayMemory by copying data from a texture to the array.
	template<typename T>
	CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(TextureMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>* CudaArrayMemory<T,3>::operator=(TextureMemory<T,3>* copy)" << std::endl;
#endif
		this->copyFrom(copy);

		return this;
	}

	// Destructor.
	template<typename T>
	CudaArrayMemory<T,3>::~CudaArrayMemory()
	{
#ifdef _DEBUG
		std::cout << "CudaArrayMemory<T,3>::~CudaArrayMemory()" << std::endl;
#endif
	}

	// Free memory in the CudaArray.
	template<typename T>
	void CudaArrayMemory<T,3>::freeMemory()
	{
#ifdef _DEBUG
		std::cout << "void CudaArrayMemory<T,3>::freeMemory()" << std::endl;
#endif
		// Free the cudaArray.
		cudaFreeArray(this->array);

		// Free the dimension size on the device.
		cudaFree(this->sizeDimGPU);

		// Reset values.
		this->array = NULL;
		this->size = 0;
		this->sizeDim = DimensionSizeVector(3);
	}

	// Print data in cudaArray to stdout.
	template<typename T>
	void CudaArrayMemory<T,3>::print()
	{
#ifdef _DEBUG
		std::cout << "void CudaArrayMemory<T,3>::print()" << std::endl;
#endif
		// Copy cudaArray to the host.
		HostMemory<T,3> h(this);

		// Print out host data.
		h.print();

		// Free temporary host data.
		h.freeMemory();
	}

	// Print data at specified index in cudaArray to stdout.
	template<typename T>
	void CudaArrayMemory<T,3>::print(DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "void CudaArrayMemory<T,3>::print(DimensionSizeVector& dim)" << std::endl;
#endif
		// Copy cudaArray to the host.
		HostMemory<T,3> h(this);

		// Print out host data at index.
		h.print(dim);

		// Free temporary host data.
		h.freeMemory();
	}

	// Allocate memory on the device for the cudaArray.
	template<typename T>
	bool CudaArrayMemory<T,3>::allocateMemory(DimensionSizeVector& dim)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::allocateMemory(DimensionSizeVector& dim)" << std::endl;
#endif
		// Boundary check dimensions.
		for(unsigned int i=0; i<3; i++) if(dim[i] < 0) return false;

		// Set the width, height, depth.
		int width = dim[0];
		int height = dim[1];
		int depth = dim[2];

		// Create a channel description of type T.
		this->channelDesc = cudaCreateChannelDesc<T>();

		// Specify the size of the array with cudaExtent.
		this->extent = make_cudaExtent(width, height, depth);

		// Mallloc the 3D array on the device.
		if(cudaMalloc3DArray(&this->array, &this->channelDesc, this->extent) == cudaSuccess) {
			// Set the size of the array.
			this->setSize(dim);
			return true;
		}

		return false;
	}

	// Copy data from the host to the cudaArray.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyFrom(HostMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyFrom(HostMemory<T,3>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for the array.
		if(this->size != copy->size) {
			if(this->array != NULL) this->freeMemory();
			this->allocateMemory(copy->sizeDim);
		}

		// Setup copy parameters.
		cudaMemcpy3DParms copyparms = {0};

		// srcPtr requires a pointer to pitched memory so we create a pitch for our memory.
		copyparms.srcPtr = make_cudaPitchedPtr((void*)copy->memory, sizeof(T) * this->extent.width, this->extent.width, this->extent.height);

		// Set the array as the destination.
		copyparms.dstArray = this->array;
		copyparms.extent = this->extent;

		// Copy from the host to the device.
		copyparms.kind = cudaMemcpyHostToDevice;

		// Copy data.
		if(cudaMemcpy3D(&copyparms) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from a device to the cudaArray.
	// Method for copying data specified in copy's method.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyFrom(DeviceMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyFrom(DeviceMemory<T,3>* copy)" << std::endl;
#endif
		return copy->copyTo(this);
	}

	// Copy data from a global to the cudaArray.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyFrom(GlobalMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyFrom(GlobalMemory<T,3>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for the array.
		if(this->size != copy->size) {
			if(this->array != NULL) this->freeMemory();
			this->allocateMemory(copy->sizeDim);
		}

		std::cout << "error - cudaarray::copyfrom(device) - bug found, needs to be fixed" << std::endl;

		// srcPtr must be aligned with cudaArray. needs to be pitched or malloc3d.

		// Setup copy parameters.
		cudaMemcpy3DParms copyparms = {0};

		// srcPtr requires a pointer to pitched memory so we create a pitch for our memory.
		copyparms.srcPtr = make_cudaPitchedPtr((void*)copy->memory, sizeof(T) * this->extent.width, this->extent.width, this->extent.height);

		// Set the array as the destination.
		copyparms.dstArray = this->array;
		copyparms.extent = this->extent;

		// Copy from the device to the device.
		copyparms.kind = cudaMemcpyDeviceToDevice;

		// Copy data.
		if(cudaMemcpy3D(&copyparms) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from a cudaArray to the cudaArray.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyFrom(CudaArrayMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyFrom(CudaArrayMemory<T,3>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for the array.
		if(this->size != copy->size) {
			if(this->array != NULL) this->freeMemory();
			this->allocateMemory(copy->sizeDim);
		}

		// Setup copy parameters.
		cudaMemcpy3DParms copyparms = {0};

		// Set the copy's array as the source.
		copyparms.srcArray = copy->array;

		// Set the array as the destination.
		copyparms.dstArray = this->array;
		copyparms.extent = this->extent;

		// Copy from the device to the device.
		copyparms.kind = cudaMemcpyDeviceToDevice;

		// Copy data.
		if(cudaMemcpy3D(&copyparms) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from a texture to the cudaArray.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyFrom(TextureMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyFrom(TextureMemory<T,3>* copy)" << std::endl;
#endif
		// Copy cudaArray in texture to the cudaArray.
		return this->copyFrom(&copy->cudaArray);
	}

	// Copy data from the cudaArray to the host.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyTo(HostMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyTo(HostMemory<T,3>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for the host.
		if(this->size != copy->size) {
			if(copy->memory != NULL) copy->freeMemory();
			copy->allocateMemory(this->sizeDim);
		}

		// Setup copy parameters.
		cudaMemcpy3DParms copyparms = {0};

		// Set the array as the source.
		copyparms.srcArray = this->array;

		// dstPtr requires a pointer to pitched memory so we create a pitch for our memory.
		copyparms.dstPtr = make_cudaPitchedPtr((void*)copy->memory, sizeof(T) * this->extent.width, this->extent.width, this->extent.height);
		copyparms.extent = this->extent;

		// Copy from the device to the host.
		copyparms.kind = cudaMemcpyDeviceToHost;

		if(cudaMemcpy3D(&copyparms) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from the cudaArray to the host.
	// Method for copying data specified in copy's method.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyTo(DeviceMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyTo(DeviceMemory<T,3>* copy)" << std::endl;
#endif
		return copy->copyFrom(this);
	}

	// Copy data from the cudaArray to a global.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyTo(GlobalMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyTo(GlobalMemory<T,3>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for a global.
		if(this->size != copy->size) {
			if(copy->memory != NULL) copy->freeMemory();
			copy->allocateMemory(this->sizeDim);
		}

		std::cout << "error - cudaarray::copyto(device) - bug found, needs to be fixed" << std::endl;

		// dstPtr must be aligned with cudaArray. needs to be pitched or malloc3d.

		// Setup copy parameters.
		cudaMemcpy3DParms copyparms = {0};

		// Set the array as the source.
		copyparms.srcArray = this->array;

		// dstPtr requires a pointer to pitched memory so we create a pitch for our memory.
		copyparms.dstPtr = make_cudaPitchedPtr((void*)copy->memory, sizeof(T) * this->extent.width, this->extent.width, this->extent.height);
		copyparms.extent = this->extent;

		// Copy from the device to the device
		copyparms.kind = cudaMemcpyDeviceToDevice;

		// Copy data.
		if(cudaMemcpy3D(&copyparms) == cudaSuccess) return true;
		else return false;
	}

	// Copy data from the cudaArray to a cudaArray.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyTo(CudaArrayMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyTo(CudaArrayMemory<T,3>* copy)" << std::endl;
#endif
		// Only allocate memory if memory has not been allocated for a cudaArray.
		if(this->size != copy->size) {
			if(copy->memory != NULL) copy->freeMemory();
			copy->allocateMemory(this->sizeDim);
		}

		// Setup copy parameters.
		cudaMemcpy3DParms copyparms = {0};

		// Set the array as the source.
		copyparms.srcArray = this->array;

		// Set the copy array as the destination.
		copyparms.dstArray = copy->array;
		copyparms.extent = this->extent;

		// Copy from the device to the device.
		copyparms.kind = cudaMemcpyDeviceToDevice;

		// Copy data.
		if(cudaMemcpy3D(&copyparms) == cudaSuccess) return true;
			else return false;
	}

	// Copy data from the cudaArray to a texture.
	template<typename T>
	bool CudaArrayMemory<T,3>::copyTo(TextureMemory<T,3>* copy)
	{
#ifdef _DEBUG
		std::cout << "bool CudaArrayMemory<T,3>::copyTo(TextureMemory<T,3>* copy)" << std::endl;
#endif
		return copy->copyFrom(this);
	}
}
